#include "tf_modbus.h"

#include <QTimer>

//imx6Q
#include <qtextedit.h>
#include <qprogressbar.h>
#include <qtimer.h>
#include <qapplication.h>
//#include <qmessagebox.h>
#include <qstringlist.h>

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <errno.h>
#include <string.h>
#include <termio.h>


/* ----------------------------------------------------
    Author: LiuMing@2020-1-12
    CRC lookup table for CRC16 (reverse).
    Polynomial:  X16 + X15 + X2 + 1 (0x1021)
    Usage:
    1.  Init CRC to 0xffff
    2.  Index = CRC ^ Buffer[I]
    3.  CRC = (CRC >> 8) ^ CRC_table[Index]
    4.  When done, swap bytes of CRC
 ------------------------------------------------------ */
const quint16 tf_modbus::modbus_crc16_table[256] = {
    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
/*-----------------------------------------------------------------------
 * Author: LiuMing@2020-10-10
  Procedure:  ModbusCRC_16()
    Computes a CRC-16 based on the polynomial
    (initial condition = 0xffff): X16 + X15 + X2 + 1 (polynomial = 0x1021)

  Calling Syntax:
       crc = crc_16(msg, bytecnt);
  Input Parameters:
    msg               - (pointer) pointer to a byte array
    bytecnt           - (unsigned int) number of bytes in array
  Output Parameters:  None
  Return Value:
    crc               - (unsigned int) computed CRC (the CRC16 swaped ready to go in a buffer)

--------------------------------------------------------------------------*/
quint16 tf_modbus::mb_crc16(unsigned char *crcBuf, int nSize)
{
unsigned char  index;
unsigned short crc;
int i;

    //cal the CRC
    crc = 0xFFFF;                   // start with all 1's for a modbus CRC

    // process each character in the message - 2 steps per char only!
    for( i = 0; i < nSize; i++)
    {
        index = (unsigned char)crc ^ crcBuf[i];
        crc = (crc >> 8) ^ modbus_crc16_table[index];
    }
    return(crc);
}


tf_modbus::tf_modbus()
{
    slaveID = 0x01;
//    fd = tf_modbus_open();
//    qDebug()<<"tf_modbus construct function"<<endl;

//    if (fd < 0) {
//       // QMessageBox::warning(this, tr("Error"), tr("Fail to open serial port!"));
//        return ;
//     }

//    m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
//    connect (m_notifier, SIGNAL(activated(int)), this, SLOT(remoteDataIncoming()));

    //connect(uart_device, SIGNAL(error(QSerialPort::SerialPortError)),this, SLOT(handleError(QSerialPort::SerialPortError)));
}
tf_modbus::~tf_modbus()
{
   // delete uart_device;
    qDebug()<<"tf_modbus destruction"<<endl;
}

//void tf_modbus::remoteDataIncoming()
//{
//        char c;
//        if (read(fd, &c, sizeof c) != 1) {
//               // QMessageBox::warning(this, tr("Error"), tr("Receive error!"));
//                return;
//        }
//        recvArr += c;
//}


bool tf_modbus::tf_modbusDeviceHandle(bool isUiButtonConnect)
{
    if(!isUiButtonConnect)
    {
       fd = tf_modbus_open();
       if(fd>0)
         uiButtonConnectStus = true;
       else
         uiButtonConnectStus = false;
    }

   return uiButtonConnectStus;
}

int tf_modbus::tf_modbus_open()
{
    int fdd = -1;
    const char *devName = "/dev/ttymxc2";
    fdd = ::open(devName, O_RDWR|O_NONBLOCK);
    if (fdd < 0) {
            return -1;
            qDebug()<<"open uart fail"<<endl;
           // ui->statusBar->showMessage("can't open /dev/ttymxc2");
    }
    termios serialAttr;
    memset(&serialAttr, 0, sizeof serialAttr);
    serialAttr.c_iflag = IGNPAR;
    serialAttr.c_cflag = B115200 | HUPCL | CS8 | CREAD | CLOCAL;
    serialAttr.c_cc[VMIN] = 1;
    if (tcsetattr(fdd, TCSANOW, &serialAttr) != 0) {
            return -1;
            qDebug()<<"tcsetattr ttymxc2 error"<<endl;
    }
    return fdd;
}
void tf_modbus::tf_modbus_close()
{


    //delete uart_device;
}

void tf_modbus::serialWirte(unsigned char *buf,int buf_Len)
{
    if(fd == -1)
        return;

    if(fd>0)
    {
        ::write(fd,(char *)buf, buf_Len);
    }
    else
    {
        qDebug()<<"tty is not open"<<endl;
    }
}


/* Non-block delay */
void tf_modbus::mb_delay(int mSec)
{
    QEventLoop loop;
    QTimer::singleShot(mSec, &loop, SLOT(quit()));
    loop.exec();
}

/*

  return: read success:0   read failure: negative value
*/
int tf_modbus::sendReadHoldingReg(uint16_t *readVal,quint16 serverAddr)
{
    //uart_device->clear(); //clear serial dirty buffer

    QByteArray recvArr;
    uint8_t recvBuf[20];
    uint8_t recvLenth = 0;

    std::vector<uint8_t> buf;
    //std::vector<uint8_t>::iterator it;
    uint16_t crc_val = 0;
    uint16_t MB_ADDR = serverAddr;
    uint16_t READ_CNT = 1;
    buf.push_back(slaveID);
    buf.push_back(MB_FUNC_RD_HOLDING);
    buf.push_back(MB_ADDR >> 8);
    buf.push_back(MB_ADDR & 0xff);
    buf.push_back(READ_CNT >> 8);
    buf.push_back(READ_CNT & 0xff);
    crc_val = mb_crc16(&buf[0],buf.size());
    buf.push_back(crc_val & 0xff);
    buf.push_back(crc_val >> 8);
    serialWirte(&buf[0],buf.size());

    mb_delay(50); //Adjust this delay value


    if(!recvArr.isEmpty())
    {

        memset(recvBuf, 0, sizeof(recvBuf));
        recvLenth = recvArr.length();
        memcpy(recvBuf,recvArr,recvArr.length());
        recvArr.clear();

  /* start parse */
        if(recvBuf[0] != slaveID)
        {
            qDebug()<<"slave id err"<<endl;
        }
        else
        {
            uint16_t  calc_crc = mb_crc16(recvBuf, (recvLenth-2));
            if ( calc_crc != ((recvBuf[recvLenth-1] << 8) | (recvBuf[recvLenth-2])))
            {
              memset(recvBuf, 0, sizeof(recvBuf)); //reset recvBuf
              qDebug()<<"crc err"<<endl;
              return -2;
            }

            if(recvBuf[1] == 0x03)
            {
                quint16 regValue = (recvBuf[3] << 8) | recvBuf[4];
                *readVal = regValue;
                return 0;
            }
        }
    }
    return -1;
}

/*

  return: read success:0   read failure: negative value
*/
int tf_modbus::sendReadMultiHoldingReg(uint16_t *readBuf, quint16 serverAddr, quint16 reg_num)
{
    //uart_device->clear(); //clear serial dirty buffer

    QByteArray recvArr;
    //uint8_t recvBuf[20];
    std::vector<uint8_t> recvBuf;
    uint8_t recvLenth = 0;

    std::vector<uint8_t> buf;
    //std::vector<uint8_t>::iterator it;
    uint16_t crc_val = 0;
    uint16_t MB_ADDR = serverAddr;
    uint16_t READ_CNT = reg_num;
    buf.push_back(slaveID);
    buf.push_back(MB_FUNC_RD_HOLDING);
    buf.push_back(MB_ADDR >> 8);
    buf.push_back(MB_ADDR & 0xff);
    buf.push_back(READ_CNT >> 8);
    buf.push_back(READ_CNT & 0xff);
    crc_val = mb_crc16(&buf[0],buf.size());
    buf.push_back(crc_val & 0xff);
    buf.push_back(crc_val >> 8);
    serialWirte(&buf[0],buf.size());



    mb_delay(50); //Adjust this delay value

    if(!recvArr.isEmpty())
    {
        recvBuf.clear();
        recvLenth = recvArr.length();
        //memcpy(recvBuf,recvArr,recvArr.length());
        for(int i=0;i<recvLenth;i++)
        {
            recvBuf.push_back(recvArr[i]);
        }
        recvArr.clear();

  /* start parse */
        if(recvBuf[0] != slaveID)
        {
            qDebug()<<"slave id err"<<endl;
            return -3;
        }
        else
        {
            uint16_t  calc_crc = mb_crc16(&recvBuf[0], (recvLenth-2));
            if ( calc_crc != ((recvBuf[recvLenth-1] << 8) | (recvBuf[recvLenth-2])))
            {
              //memset(recvBuf, 0, sizeof(recvBuf)); //reset recvBuf
              recvBuf.clear();
              qDebug()<<"crc err"<<endl;
              return -2;
            }

            if(recvBuf[1] == 0x03)
            {
                for(int j=0;j<reg_num;j++)
                {
                    readBuf[j] = (recvBuf[2*(j+1)+1] << 8) | recvBuf[2*(j+1)+2];
                }
                return 0;
            }
        }
    }

    return -1;
}

/*

  return: read success:0   read failure: negative value
*/
int tf_modbus::sendReadFloatReg(float *readVal, quint16 serverAddr)
{
    //uart_device->clear();

    //QByteArray recvArr;
    uint8_t recvBuf[20];
    uint8_t recvLenth = 0;

    std::vector<uint8_t> buf;
    //std::vector<uint8_t>::iterator it;
    uint16_t crc_val = 0;
    uint16_t MB_ADDR = serverAddr;
    uint16_t READ_BYTE_CNT = 2;
    buf.push_back(slaveID);
    buf.push_back(MB_FUNC_RD_HOLDING);
    buf.push_back(MB_ADDR >> 8);
    buf.push_back(MB_ADDR & 0xff);
    buf.push_back(READ_BYTE_CNT >> 8);
    buf.push_back(READ_BYTE_CNT & 0xff);
    crc_val = mb_crc16(&buf[0],buf.size());
    buf.push_back(crc_val & 0xff);
    buf.push_back(crc_val >> 8);
    serialWirte(&buf[0],buf.size());

    mb_delay(50); //Adjust this delay time according to the quantity of register

    if(recvArr.isEmpty() == false)
    {
        memset(recvBuf, 0, sizeof(recvBuf));
        recvLenth = recvArr.length();
        memcpy(recvBuf,recvArr,recvArr.length());
        recvArr.clear();

  /* start parse */
        if(recvBuf[0] != slaveID)
        {
            qDebug()<<"slave id err"<<endl;
             qDebug()<<"recvBuf[0]= "<<recvBuf[0]<<endl;
            return -3;
        }
        else
        {
            uint16_t  calc_crc = mb_crc16(recvBuf, (recvLenth-2));
            if ( calc_crc != ((recvBuf[recvLenth-1] << 8) | (recvBuf[recvLenth-2])))
            {
              memset(recvBuf, 0, sizeof(recvBuf)); //reset recvBuf
              qDebug()<<"crc err"<<endl;
              return -2;
            }

            if(recvBuf[1] == 0x03)
            {
                DATA_TYPE_t union_data;
                //memcpy(union_data.buffer, &recvBuf[3], 4);
                union_data.buffer[0] = recvBuf[4];
                union_data.buffer[1] = recvBuf[3];
                union_data.buffer[2] = recvBuf[6];
                union_data.buffer[3] = recvBuf[5];

                *readVal = union_data.data.reg_flo;
                return 0;
            }
        }
    }

    qDebug()<<"EMPTY"<<endl;
    return -1;
}

/*
  param:
    serverAddr: start addr
    reg_num: float register nums

  return: read success:0   read failure: negative value
*/
int tf_modbus::sendReadMultiFloatReg(float *readBuf, quint16 serverAddr, quint16 reg_num)
{
    //uart_device->clear();

    //QByteArray recvArr;
    //uint8_t recvBuf[20];
    std::vector<uint8_t> recvBuf;
    uint8_t recvLenth = 0;

    std::vector<uint8_t> buf;
    //std::vector<uint8_t>::iterator it;
    uint16_t crc_val = 0;
    uint16_t MB_ADDR = serverAddr;
    uint16_t READ_BYTE_CNT = (reg_num*2);
    buf.push_back(slaveID);
    buf.push_back(MB_FUNC_RD_HOLDING);
    buf.push_back(MB_ADDR >> 8);
    buf.push_back(MB_ADDR & 0xff);
    buf.push_back(READ_BYTE_CNT >> 8);
    buf.push_back(READ_BYTE_CNT & 0xff);
    crc_val = mb_crc16(&buf[0],buf.size());
    buf.push_back(crc_val & 0xff);
    buf.push_back(crc_val >> 8);
    serialWirte(&buf[0],buf.size());

//    qDebug()<<"send read request..."<<endl;
//    for(int j=0;j<buf.size();j++)
//    {
//        qDebug()<<hex<<buf[j];
//    }

    mb_delay(100); //Adjust this delay time according to the quantity of register

    if(recvArr.isEmpty() == false)
    {

        //memset(recvBuf, 0, sizeof(recvBuf));
        recvLenth = recvArr.length();
        //memcpy(recvBuf,recvArr,recvArr.length());
        recvBuf.clear();
        for(int i=0;i<recvLenth;i++)
        {
            recvBuf.push_back(recvArr[i]);
        }

        recvArr.clear();

//        qDebug()<<"The receive data: "<<endl;
//        for(int j=0;j<recvLenth;j++)
//        {
//            qDebug()<<hex<<recvBuf[j];
//        }

  /* start parse */
        if(recvBuf[0] != slaveID)
        {
            qDebug()<<"slave id err"<<endl;
            return -3;
        }
        else
        {
            uint16_t  calc_crc = mb_crc16(&recvBuf[0], (recvLenth-2));
            if ( calc_crc != ((recvBuf[recvLenth-1] << 8) | (recvBuf[recvLenth-2])))
            {
              //memset(recvBuf, 0, sizeof(recvBuf)); //reset recvBuf
              recvBuf.clear();
              qDebug()<<"crc err"<<endl;
              return -2;
            }

            if(recvBuf[1] == 0x03)
            {
                for(int j=0;j<reg_num;j++)
                {
                    DATA_TYPE_t union_data;
                    //memcpy(union_data.buffer, &recvBuf[3], 4);
                    union_data.buffer[0] = recvBuf[4*(j+1)];
                    union_data.buffer[1] = recvBuf[4*(j+1)-1];
                    union_data.buffer[2] = recvBuf[4*(j+1)+2];
                    union_data.buffer[3] = recvBuf[4*(j+1)+1];
                    readBuf[j] = union_data.data.reg_flo;
                }
            }
        }
    }
    else
    {
        return -1;
    }

    return 0;
}

void tf_modbus::sendWriteHoldingReg(quint16 serverAddr, quint16 value)
{
    std::vector<uint8_t> buf;
    uint16_t crc_val = 0;
    uint16_t MB_ADDR = serverAddr;
    uint16_t REG_VALUE = value;
    buf.push_back(slaveID);
    buf.push_back(MB_FUNC_WR_SINGLE);
    buf.push_back(MB_ADDR >> 8);
    buf.push_back(MB_ADDR & 0xff);
    buf.push_back(REG_VALUE >> 8);
    buf.push_back(REG_VALUE & 0xff);
    crc_val = mb_crc16(&buf[0],buf.size());
    buf.push_back(crc_val & 0xff);
    buf.push_back(crc_val >> 8);
    serialWirte(&buf[0],buf.size());
    mb_delay(100);
}

void tf_modbus::sendWriteMultiHoldingReg(uint16_t *writeBuf, quint16 serverAddr, quint16 reg_quantity)
{
    std::vector<uint8_t> buf;
    uint16_t crc_val = 0;
    uint16_t MB_ADDR = serverAddr;
    uint16_t REG_NUM = reg_quantity;
    uint8_t  Byte_Count = (REG_NUM*2);
    buf.push_back(slaveID);
    buf.push_back(MB_FUNC_WR_MULTI_REGS);
    buf.push_back(MB_ADDR >> 8);
    buf.push_back(MB_ADDR & 0xff);
    buf.push_back(REG_NUM >> 8);
    buf.push_back(REG_NUM & 0xff);
    buf.push_back(Byte_Count);

    for(int i=0;i<REG_NUM;i++)
    {
        buf.push_back(writeBuf[i] >> 8);
        buf.push_back(writeBuf[i] & 0xff);
    }

    crc_val = mb_crc16(&buf[0],buf.size());
    buf.push_back(crc_val & 0xff);
    buf.push_back(crc_val >> 8);
    serialWirte(&buf[0],buf.size());
    mb_delay(100);
}

void tf_modbus::sendWriteFloatReg(quint16 serverAddr, float value)
{
    std::vector<uint8_t> buf;
    uint16_t crc_val = 0;
    uint16_t MB_ADDR = serverAddr;
   // uint16_t REG_VALUE = value;
    uint16_t REG_QUANTITY = 2;
    DATA_TYPE_t union_data;
    union_data.data.reg_flo = value;

    buf.push_back(slaveID);
    buf.push_back(MB_FUNC_WR_MULTI_REGS);
    buf.push_back(MB_ADDR >> 8);
    buf.push_back(MB_ADDR & 0xff);
    buf.push_back(REG_QUANTITY >> 8);
    buf.push_back(REG_QUANTITY & 0xff);
    buf.push_back(REG_QUANTITY * 2);       //Byte Count
    buf.push_back(union_data.buffer[1]); //Value
    buf.push_back(union_data.buffer[0]);
    buf.push_back(union_data.buffer[3]);
    buf.push_back(union_data.buffer[2]);

    crc_val = mb_crc16(&buf[0],buf.size());
    buf.push_back(crc_val & 0xff);
    buf.push_back(crc_val >> 8);
    serialWirte(&buf[0],buf.size());

    mb_delay(100);
}

void tf_modbus::sendReadRequest(QVector<quint16> &buf,quint16 startAddr, qint16 registerNum)
{

}

void tf_modbus::sendWriteRequest()
{

    //uart_device->write((char *)buf, buf_Len);
}



